package application

import (
	"fabric-go-sdk/sdk/sdkInfo/channelInfo"
	"fabric-go-sdk/sdk/sdkInfo/orgInfo"
	"fmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
)

// InstallCC 安装链码
func (a *Application) InstallCC(channelId string, orgName string, chaincodeID string, peerUrl string) error {
	// 检查参数
	if _, ok := a.Channels[channelId]; !ok {
		return fmt.Errorf("InstallCC err:通道 %v 不存在.", channelId)
	}
	if _, ok := a.Channels[channelId].Orgs[orgName]; !ok {
		return fmt.Errorf("InstallCC err:通道 %v 中不存在组织 %v .", channelId, orgName)
	}
	// 获取org实例
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		return fmt.Errorf("InstallCC err:获取org实例失败.")
	}
	// 通过chaincodeID获取chaincode实例
	if _, ok := a.Channels[channelId].Chaincode[chaincodeID]; !ok {
		return fmt.Errorf("InstallCC err:通道 %v 中不存在链码 %v .", channelId, chaincodeID)
	}
	cc, ok := a.Channels[channelId].Chaincode[chaincodeID]
	if !ok {
		return fmt.Errorf("InstallCC err:获取链码实例失败.")
	}
	// 安装链码
	err := org.InstallCC(a.FabSDK, peerUrl, channelId, cc.Label, cc.Pkg)
	if err != nil {
		return fmt.Errorf("InstallCC err: %v", err)
	}
	return nil
}

// ApproveCC 批准链码
func (a *Application) ApproveCC(channelId string, orgName string, chaincodeID string) error {
	// 检查参数
	if _, ok := a.Channels[channelId]; !ok {
		return fmt.Errorf("ApproveCC err:通道 %v 不存在.", channelId)
	}
	if _, ok := a.Channels[channelId].Orgs[orgName]; !ok {
		return fmt.Errorf("ApproveCC err:通道 %v 中不存在组织 %v .", channelId, orgName)
	}
	// 获取org实例
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		return fmt.Errorf("ApproveCC err:获取org实例失败.")
	}
	// 获取orderer节点url
	ordererEndpoint := a.Orderer.Endpoint[0]
	// 获取通道的MspIds
	mspIds := []string{}
	for _, orginfo := range a.Channels[channelId].Orgs {
		mspIds = append(mspIds, orginfo.OrgMspId)
	}
	// 通过chaincodeID获取chaincode实例
	if _, ok := a.Channels[channelId].Chaincode[chaincodeID]; !ok {
		return fmt.Errorf("ApproveCC err:通道 %v 中不存在链码 %v .", channelId, chaincodeID)
	}
	cc, ok := a.Channels[channelId].Chaincode[chaincodeID]
	if !ok {
		return fmt.Errorf("ApproveCC err:获取链码实例失败.")
	}
	// 批准链码
	err := org.ApproveCC(a.FabSDK, cc.PkgID, cc.Name, cc.Version, cc.Sequence, channelId, ordererEndpoint, mspIds)
	if err != nil {
		return fmt.Errorf("ApproveCC err: %v", err)
	}
	return nil
}

// CommitCC 批准链码
func (a *Application) CommitCC(channelId string, orgName string, chaincodeID string) error {
	// 检查参数
	if _, ok := a.Channels[channelId]; !ok {
		return fmt.Errorf("CommitCC err:通道 %v 不存在.", channelId)
	}
	if _, ok := a.Channels[channelId].Orgs[orgName]; !ok {
		return fmt.Errorf("CommitCC err:通道 %v 中不存在组织 %v .", channelId, orgName)
	}
	// 获取org实例
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		return fmt.Errorf("CommitCC err:获取org实例失败.")
	}
	// 获取orderer节点url
	ordererEndpoint := a.Orderer.Endpoint[0]
	// 获取通道的MspIds
	mspIds := []string{}
	for _, orginfo := range a.Channels[channelId].Orgs {
		mspIds = append(mspIds, orginfo.OrgMspId)
	}
	// 通过chaincodeID获取chaincode实例
	if _, ok := a.Channels[channelId].Chaincode[chaincodeID]; !ok {
		return fmt.Errorf("CommitCC err:通道 %v 中不存在链码 %v .", channelId, chaincodeID)
	}
	cc, ok := a.Channels[channelId].Chaincode[chaincodeID]
	if !ok {
		return fmt.Errorf("CommitCC err:获取链码实例失败.")
	}
	// 批准链码
	err := org.CommitCC(a.FabSDK, cc.Name, cc.Version, cc.Sequence, channelId, ordererEndpoint, mspIds)
	if err != nil {
		return fmt.Errorf("CommitCC err: %v", err)
	}
	return nil
}

//CheckCCCommitReadiness 链码批准情况
func (a *Application) CheckCCCommitReadiness(channelId string, orgName string, chaincodeID string) (map[string]bool, error) {
	// 检查参数
	if _, ok := a.Channels[channelId]; !ok {
		return nil, fmt.Errorf("CheckCCCommitReadiness err:通道 %v 不存在.", channelId)
	}
	if _, ok := a.Channels[channelId].Orgs[orgName]; !ok {
		return nil, fmt.Errorf("CheckCCCommitReadiness err:通道 %v 中不存在组织 %v .", channelId, orgName)
	}
	// 获取org实例
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		return nil, fmt.Errorf("CheckCCCommitReadiness err:获取org实例失败.")
	}
	// 获取通道的MspIds
	mspIds := []string{}
	for _, orginfo := range a.Channels[channelId].Orgs {
		mspIds = append(mspIds, orginfo.OrgMspId)
	}
	// 通过chaincodeID获取chaincode实例
	if _, ok := a.Channels[channelId].Chaincode[chaincodeID]; !ok {
		return nil, fmt.Errorf("CheckCCCommitReadiness err:通道 %v 中不存在链码 %v .", channelId, chaincodeID)
	}
	cc, ok := a.Channels[channelId].Chaincode[chaincodeID]
	if !ok {
		return nil, fmt.Errorf("CheckCCCommitReadiness err:获取链码实例失败.")
	}
	// 查询批准情况
	res, err := org.CheckCCCommitReadiness(a.FabSDK, cc.Name, cc.Version, cc.Sequence, channelId, mspIds)
	if err != nil {
		return nil, fmt.Errorf("CheckCCCommitReadiness err: %v", err)
	}
	return res, nil
}

// QueryCommittedCC 查询链码提交情况
func (a *Application) QueryCommittedCC(channelId string, orgName string) (res []resmgmt.LifecycleChaincodeDefinition, err error) {
	// 检查参数
	if _, ok := a.Channels[channelId]; !ok {
		return nil, fmt.Errorf("QueryCommittedCC err:通道 %v 不存在.", channelId)
	}
	//  获取org实例 若失败 则给定默认的org实例
	var org *orgInfo.OrgInfo
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		for _, orginfo := range a.Channels[channelId].Orgs {
			org = orginfo
			break
		}
	}
	// 查询
	res, err = org.QueryCommittedCC(a.FabSDK, channelId)
	if err != nil {
		return nil, fmt.Errorf("QueryCommittedCC err:%v", err)
	}
	return res, nil
}

// CreatChannel 创建通道
func (a *Application) CreatChannel(channelId string, channelCfgPath string) error {
	// 检查参数
	if channelId == "" {
		return fmt.Errorf("CreatChannel err:channelId为空.")
	}
	if _, ok := a.Channels[channelId]; ok {
		return fmt.Errorf("CreatChannel err:通道 %v 已存在.", channelId)
	}
	// 创建channel实例并加入到application中--默认使用org1创建---默认使用一个channelid来创建
	channel := channelInfo.New(channelId, channelCfgPath)
	channel.Orgs = a.Channels["mychannel"].Orgs
	channel.Orgs["Org1"].PeersUrl = []string{}
	a.Channels[channelId] = channel
	// 获取org实例--默认使用org1创建---默认使用一个channelid来创建
	org, ok := a.Channels["mychannel"].Orgs["Org1"]
	if !ok {
		return fmt.Errorf("CreatChannel err:获取org实例失败.")
	}
	// 获取组织签名--默认使用org1创建---默认使用一个channelid来创建
	signIDs, err := org.GetSigningIdentity(a.FabSDK)
	if err != nil {
		return fmt.Errorf("CreatChannel GetSigningIdentity err:%v", err)
	}
	// 创建通道
	if err := a.Orderer.CreateChannel(a.FabSDK, []msp.SigningIdentity{*signIDs}, channelId, channelCfgPath); err != nil {
		return fmt.Errorf("CreatChannel CreateChannel err: %v", err)
	}
	return nil
}

//peer节点加入通道
func (a *Application) PeerJoinChannel(channelId string, orgName string, peerURL string) error {
	// 检查参数
	if channelId == "" {
		return fmt.Errorf("PeerJoinChannel err:channelId为空.")
	}
	if peerURL == "" {
		return fmt.Errorf("PeerJoinChannel err:PeerURL为空.")
	}
	// 获取org实例
	org, ok := a.Channels[channelId].Orgs[orgName]
	if !ok {
		return fmt.Errorf("PeerJoinChannel err:获取org实例失败.")
	}
	// 获取orderer节点url
	ordererEndpoint := a.Orderer.Endpoint[0]
	// 加入通道
	err := org.PeerJoinChannel(a.FabSDK, channelId, peerURL, ordererEndpoint)
	if err != nil {
		return fmt.Errorf("PeerJoinChannel PeerJoinChannel err:%v", err)
	}
	// peer加入到app实例中
	a.Channels[channelId].Orgs[orgName].PeersUrl = append(a.Channels[channelId].Orgs[orgName].PeersUrl, peerURL)
	return nil
}
